import wx
import os
import subprocess
import StringIO
import traceback

import ConfigParser

import ren_helper

ID_EXIT = 101

ID_SELECT_DIR = 201
ID_SET_EXT = 202
ID_GO = 203

ID_LOG = 301
ID_HELP = 302
ID_ABOUT = 303

CFG_FILENAME = "renamer_config.cfg"

CFG_SECTION_CRITICAL = "General"
CFG_SECTION_CRITICAL_DIR = "Default_Dir"
CFG_SECTION_CRITICAL_EXT = "Default_Ext"

GFG_SECTION_STATISTICS = "Stats"

VERSION_NUMBER = "2.0 Beta 3"

class MainWindow(wx.Frame):
 
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, title="Renamer " + VERSION_NUMBER, style = wx.DEFAULT_FRAME_STYLE ^ (wx.RESIZE_BORDER | wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX))
        
        #Instance Variables
        
        self.rename_to = []
        self.rename_from = []
        self.workDir = "C:\\"
        self.workExt = ""
        
        self.defaultDir = ""
        self.defaultExt = ""
        
        # Read the configuration file and
        # set program defaults.
        
        if self.readConfig() == 0:
            self.workExt = self.defaultExt
            self.workDir = self.defaultDir
        
        self.panel = wx.Panel(self, wx.ID_ANY)
        
        self.CreateStatusBar()
        
        # Menu
        
        menuBar = wx.MenuBar()
        
        file = wx.Menu()
        file.Append(ID_EXIT, 'E&xit', 'Exit Application.')
        
        self.Bind(wx.EVT_MENU, self.onExit, id = ID_EXIT)
        
        operations = wx.Menu()
        
        operations.Append(ID_SELECT_DIR, '&Select Directory...', 'Select the directory from which the input files will be renamed.')
        operations.Append(ID_SET_EXT, 'Set Ex&tenson...', 'Set the default extension to append to the renamed documents.')
        operations.AppendSeparator()
        operations.Append(ID_GO, '&Go','Preform the operation.')
        
        self.Bind(wx.EVT_MENU, self.onSelectDir, id = ID_SELECT_DIR)
        self.Bind(wx.EVT_MENU, self.onGo, id = ID_GO)
        self.Bind(wx.EVT_MENU, self.onSetExtension, id = ID_SET_EXT)
        
        help = wx.Menu()
        
        help.Append(ID_HELP, '&Help', 'Shows instuctions.')
        
        menuBar.Append(file, '&File')
        menuBar.Append(operations, '&Operations')
        menuBar.Append(help, '&Help')
        
        self.SetMenuBar(menuBar)
        
        # Grid
        
        sizer_main = wx.FlexGridSizer(2, 3, 5, 10)
        
        label_in = wx.StaticText(self.panel, wx.ID_ANY, "Original:")
        label_out = wx.StaticText(self.panel, wx.ID_ANY, "Change To:")
        label_info = wx.StaticText(self.panel, wx.ID_ANY, "Info")
        
        box_height = 600
        box_width = 250
        
        self.box_in = wx.TextCtrl(self.panel, wx.ID_ANY, "", size = (box_width, box_height), style = wx.TE_MULTILINE | wx.TOP | wx.BOTTOM | wx.TE_READONLY | wx.TE_DONTWRAP)
        self.box_out = wx.TextCtrl(self.panel, wx.ID_ANY, "",size = (box_width, box_height), style = wx.TE_MULTILINE | wx.TOP | wx.BOTTOM | wx.TE_DONTWRAP)
        self.box_info = wx.TextCtrl(self.panel, wx.ID_ANY,"", size = (500, box_height), style = wx.TE_MULTILINE | wx.TOP | wx.BOTTOM | wx.TE_READONLY)
        
        self.Bind(wx.EVT_TEXT, self.onType, self.box_out)
        
        sizer_main.Add(label_in, 1, wx.ALIGN_CENTER)
        sizer_main.Add(label_out, 1, wx.ALIGN_CENTER)
        sizer_main.Add(label_info, 1, wx.ALIGN_CENTER)
        sizer_main.Add(self.box_in, 1, wx.ALIGN_CENTER)
        sizer_main.Add(self.box_out, 1, wx.ALIGN_CENTER)
        sizer_main.Add(self.box_info, 1, wx.ALIGN_CENTER)
        
        self.panel.SetSizer(sizer_main)
        sizer_main.Fit(self)
        
        if self.workDir != "":
            self.updateInFiles()
        
    def onSelectDir(self, event):
        
        dialog = wx.DirDialog(None, "Select the directory in which the original files are located.", defaultPath = self.defaultDir, style = wx.DD_DEFAULT_STYLE)
        
        if dialog.ShowModal() == wx.ID_OK:
            self.workDir = dialog.GetPath()
        
            dialog.Destroy()
            
            if self.defaultDir != self.workDir:       
                self.askSetDefault(CFG_SECTION_CRITICAL_DIR, self.workDir)
            
            self.updateInFiles()  


    def onGo(self, event):
        num_old_files = len(self.rename_from)
        num_new_files = len(self.rename_to)
        if num_old_files == num_new_files:
            
            origin_dir = os.getcwd()
            
            os.chdir(self.workDir)
            
            self.box_info.SetValue("------------Renaming------------\nNote: The characters '/ ? < > \\ : * | \"' are illegal and are automatically removed.\n\n")
            
            success = True
            
            for x in range(num_old_files):
                try:
                    os.rename(self.rename_from[x], self.rename_to[x] + self.workExt)
                    self.box_info.AppendText("Renamed " + self.rename_from[x] + " to " + self.rename_to[x] + self.workExt + " successfully.\n")
                except OSError as RenameError:
                    error = StringIO.StringIO()
                    traceback.print_exc(file=error)
                    
                    log = error.getvalue()
                    
                    error_msg = str(RenameError)
                    
                    self.box_info.AppendText("Renaming of " + self.rename_from[x] + " failed.\n" + error_msg + "\n\n")
                    success = False
            
            os.chdir(origin_dir)
            
            if success == True:
                subprocess.Popen('explorer "' + self.workDir + '"')
                self.updateInFiles()
        else:
            self.box_info.SetValue("------------Error------------\n'Original' and 'Change To' fields not of equal length. Renaming will not occur.\nLength of 'Original': " + str(num_old_files) + "\nLength of 'Change To': " + str(num_new_files))

    def onExit(self, event):
        self.Close(True)
        
    def onType(self, event):
        string = event.GetString()
        
        names = string.split("\n")
        
        converted = []
        
        for x in names:
            ascii_name = x.encode("ASCII").strip()
            if ascii_name != "":
                converted.append(ren_helper.remove_illegal_chars(ascii_name.strip("\t")))
        
        self.rename_to = converted
        
        if "\t" in string:
            new_string = ""
            
            for x in self.rename_to:
                new_string += x + "\n"
            
            self.box_out.SetValue(new_string)
            
    def onSetExtension(self, event):
        extension_dialog = wx.TextEntryDialog(self,
                                               "Please enter the extension you would like to append to files.",
                                               "Enter Extension",
                                               self.defaultExt,
                                               wx.OK | wx.CANCEL)
        
        if extension_dialog.ShowModal() == wx.ID_OK:
            self.workExt = extension_dialog.GetValue()
            if self.workExt != self.defaultExt:
                self.askSetDefault(CFG_SECTION_CRITICAL_EXT, self.workExt)

    def askSetDefault(self, variable, value):
        set_default = wx.MessageDialog(self, "Would you like Renamer to remember this for future use?", "Remember?", wx.YES_NO)       
        if set_default.ShowModal() == wx.ID_YES:
            self.setDefaultOption(variable, value)
        
        set_default.Destroy()

    def setDefaultOption(self, variable, value):
        config = ConfigParser.ConfigParser()
        
        config.read(CFG_FILENAME)
        
        try:
            config.set(CFG_SECTION_CRITICAL, variable, value)
        
        except ConfigParser.NoSectionError:
            
            config.add_section(CFG_SECTION_CRITICAL)
            config.set(CFG_SECTION_CRITICAL, variable, value)
        
        finally:
            with open(CFG_FILENAME, 'wb') as configfile:
                config.write(configfile)
    
    def readConfig(self):
        """
        Read configuration file.
        If the file is not present or unreadable, returns 1, otherwise 0.
        """
        
        config = ConfigParser.ConfigParser()
        
        config.read(CFG_FILENAME)
        
        try:
            self.defaultDir = config.get(CFG_SECTION_CRITICAL, CFG_SECTION_CRITICAL_DIR)
            self.defaultExt = config.get(CFG_SECTION_CRITICAL, CFG_SECTION_CRITICAL_EXT)
        except ConfigParser.NoSectionError:
            return 1
        except ConfigParser.NoOptionError:
            return 1
        
        return 0
    
    def updateInFiles(self):
        file_list = []
        
        try:
            os.listdir(self.workDir)
        except WindowsError:    #If workDir no longer exists, delete the default.
            self.workDir = "C:\\"
            self.defaultDir = ""
            self.setDefaultOption(CFG_SECTION_CRITICAL_DIR, "")
        else:
            for x in os.listdir(self.workDir):
                if x != "":
                    file_list.append(x)
                
            file_str = ""
                
            for x in file_list:
                file_str += x + "\n"
                
            self.rename_from = file_list 
                
            self.box_in.SetValue(file_str)
    
    
if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = MainWindow().Show()
    app.MainLoop()
    